import { GraphDataModel } from "./graphDataModel";
import GraphBase from "./shape/graphBase";
import RectNodeGraph from "./shape/rect";
import EllipseNodeGraph from "./shape/ellipse";
import PolyLineNodeGraph from "./shape/polyline";
import BezierCurveNodeGraph from "./shape/bezierCurve";
import EventEmitter from "./eventEmitter";
import { throttle } from "./utils";
import ControlPoints from "./pointController/controlPoints";
import { getScale } from "./graphviewState";
export class SelectedInteractor extends EventEmitter {
  target: HTMLCanvasElement;
  dataModel: GraphDataModel;
  pointsController!: ControlPoints;
  ctx: CanvasRenderingContext2D | null;
  currentPoint: { x: number; y: number } = { x: 0, y: 0 };
  hoverTarget!: GraphBase | null;
  selectedObjSet = new Set<GraphBase>();
  constructor(target: HTMLCanvasElement, dataModel: GraphDataModel) {
    super();
    this.target = target;
    this.ctx = this.target.getContext("2d");
    this.dataModel = dataModel;
    this.initInteractor();
    this.initControlPoints();
  }
  initControlPoints() {
    this.pointsController = new ControlPoints(this.target);
    this.pointsController.on("redraw", () => {
      this.emit("redraw");
    });
    this.pointsController.on(
      "resize",
      (rect: { x: number; y: number; width: number; height: number }) => {
        this.onControlPointResize(rect);
      }
    );
    this.pointsController.on("drag", (translate: number[]) => {
      this.translateSelectedObj(translate[0], translate[1]);
      this.pointsController.updateControlPoints(this.getBoundsRect());
    });
    this.pointsController.on("drop", () => {
      this.onSelectedDrop();
    });
  }
  // 获取选中图形的外层矩形框
  getBoundsRect(): { x: number; y: number; width: number; height: number } {
    const rect = {
      x: 0,
      y: 0,
      width: 0,
      height: 0,
    };
    const objs = Array.from(this.selectedObjSet.values());
    const firstRect = objs[0].getRect();
    rect.x = firstRect.x;
    rect.y = firstRect.y;
    rect.width = firstRect.width;
    rect.height = firstRect.height;
    for (let i = 1; i < objs.length; i++) {
      const node = objs[i];
      const rectRightBottomX = rect.x + rect.width;
      const rectRightBottomY = rect.y + rect.height;
      const nodeRect = node.getRect();
      const nodeRectRightBottomX = nodeRect.x + nodeRect.width;
      const nodeRectRightBottomY = nodeRect.y + nodeRect.height;
      if (nodeRect.x < rect.x) {
        rect.x = nodeRect.x;
      }
      if (nodeRect.y < rect.y) {
        rect.y = nodeRect.y;
      }
      if (rectRightBottomX < nodeRectRightBottomX) {
        rect.width = nodeRectRightBottomX - rect.x;
      }
      if (rectRightBottomY < nodeRectRightBottomY) {
        rect.height = nodeRectRightBottomY - rect.y;
      }
    }
    return rect;
  }
  destroy() {
    this.target.removeEventListener("mousedown", this.handleMouseDown);
    this.target.removeEventListener("mouseup", this.handleMouseUp);
    this.target.removeEventListener("mousemove", this.handleMouseMove);
    this.pointsController.destroy();
    this.clear();
  }
  initInteractor() {
    this.handleMouseDown = this.handleMouseDown.bind(this);
    this.handleMouseUp = this.handleMouseUp.bind(this);
    this.handleMouseMove = throttle(this.handleMouseMove, 16, this);
    this.target.addEventListener("mousedown", this.handleMouseDown);
    this.target.addEventListener("mouseup", this.handleMouseUp);
    this.target.addEventListener("mousemove", this.handleMouseMove);
  }
  setCursor(cursorStyle: string) {
    this.target.style.cursor = cursorStyle;
  }
  handleMouseDown(e: MouseEvent) {
    const hoverPoint = this.pointsController.getHoverPoint();
    if (!e.ctrlKey && !hoverPoint) {
      // 如果鼠标按下时没有在控制点上,也没有按ctrl键,就清空选中数据
      this.selectedObjSet.clear();
    }
    if (this.hoverTarget) {
      this.selectedObjSet.add(this.hoverTarget);
    }
    // redraw只会重绘图元,不会重绘控制点
    this.emit("redraw");
    // 如果有选中,才会重绘控制点
    if (this.selectedObjSet.size > 0) {
      // 控制点记录控制对象
      this.pointsController.setControlTarget(
        Array.from(this.selectedObjSet.values())
      );
      this.pointsController.updateControlPoints(this.getBoundsRect());
      this.emit(
        "selectedChange",
        Array.from(this.selectedObjSet.values()).pop()
      );
    } else {
      // 如果没有选中,控制点清除控制对象
      this.pointsController.setControlTarget(null);
      this.emit("selectedChange", null);
    }
  }
  handleMouseUp(e: MouseEvent) {}
  handleMouseMove(e: MouseEvent) {
    // 去除缩放对鼠标获取点坐标的影响
    const scale = getScale();
    const x = e.offsetX / scale;
    const y = e.offsetY / scale;
    this.currentPoint.x = x;
    this.currentPoint.y = y;
    this.hoverTarget = this.findHover(x, y);
    const hoverPoint = this.pointsController.getHoverPoint();
    if (this.hoverTarget && !hoverPoint) {
      this.setCursor("pointer");
    } else if (!this.hoverTarget && !hoverPoint) {
      this.setCursor("default");
    }
  }
  // 根据鼠标位置获取鼠标悬浮的最上层图形对象
  findHover(x: number, y: number): null | GraphBase {
    const hoverTargetArr: GraphBase[] = [];
    this.dataModel.each((node: GraphBase) => {
      if (node.contain(x, y)) {
        hoverTargetArr.push(node);
      }
    });
    if (hoverTargetArr.length === 0) {
      return null;
    } else if (hoverTargetArr.length === 1) {
      return hoverTargetArr[0];
    } else {
      let lastId = hoverTargetArr[0].getId();
      let lastNode = hoverTargetArr[0];
      for (let i = 1; i < hoverTargetArr.length; i++) {
        const node = hoverTargetArr[i];
        if (node.getId() > lastId) {
          lastNode = node;
        }
      }
      return lastNode;
    }
  }
  // 响应控制点的改变
  onControlPointResize(rect: {
    x: number;
    y: number;
    width: number;
    height: number;
  }) {
    const originRect = this.getBoundsRect();
    const translate = [rect.x - originRect.x, rect.y - originRect.y];
    const scale = [
      rect.width / originRect.width,
      rect.height / originRect.height,
    ];
    this.selectedObjSet.forEach((node) => {
      node.offset(translate[0], translate[1]);
      node.scale(scale[0], scale[1]);
    });

    this.emit("propertyChange");
  }
  // 移动选中对象
  translateSelectedObj(translateX: number, translateY: number) {
    this.selectedObjSet.forEach((node) => {
      node.translate(translateX, translateY);
    });
    this.emit("propertyChange");
  }
  // 结束拖拽选中对象
  onSelectedDrop() {
    this.selectedObjSet.forEach((node) => {
      const rect = node.getRect();
      if (node.type === "polyline" || node.type === "bezier") {
        (node as PolyLineNodeGraph | BezierCurveNodeGraph).saveOriginPoints();
      } else {
      }
      node.setOriginRect(rect.x, rect.y, rect.width, rect.height);
    });
  }
  // 改变选中对象属性
  changeProperty(propertyName: string, propertyValue: any) {
    const lastSelectedNode = Array.from(this.selectedObjSet.values()).pop();
    switch (lastSelectedNode?.type) {
      case "rect":
        (lastSelectedNode as RectNodeGraph).changeProperty(
          propertyName,
          propertyValue
        );
        break;
      case "ellipse":
        (lastSelectedNode as EllipseNodeGraph).changeProperty(
          propertyName,
          propertyValue
        );
        break;
      case "polyline":
        (lastSelectedNode as PolyLineNodeGraph).changeProperty(
          propertyName,
          propertyValue
        );
        break;
      case "bezier":
        (lastSelectedNode as BezierCurveNodeGraph).changeProperty(
          propertyName,
          propertyValue
        );
        break;
      default:
        break;
    }
    this.pointsController.updateControlPoints(this.getBoundsRect());
    this.emit("redraw");
    this.pointsController.drawControlPoints();
  }
  // 绘制控制点
  drawControlPoints() {
    if (this.selectedObjSet.size > 0) {
      this.pointsController.updateControlPoints(this.getBoundsRect());
      this.pointsController.drawControlPoints();
    }
  }
}
